use poker_lib::PokerCard;

use crate::{
    card_weight::CardWeight, round::Round, rule::{
        EmAIRule, IRule, RuleAttackBag, RuleAttackNilAndAvoidBags,
        RuleAttackNilAndReachBid, RuleAvoidBags, RuleCoverNil, RuleEasy, RulePlayNil, RuleReachBid,
    }, rule_solo::{
        RuleAttackBagSolo, RuleAttackNilAndAvoidBagsSolo, RuleAttackNilAndReachBidSolo,
        RuleAvoidBagsSolo, RuleCoverNilSolo, RuleReachBidSolo,
    }, seat::Seat, table::Table, turn::{TurnHandPileState, TurnState}, utils::Utils
};
//AI 多模式打牌
pub trait IAiPlayMode {
    fn get_turn_trick_state(
        &self,
        seat_id: usize,
        table: &Table,
        round: &Round,
        _playable: &Vec<PokerCard>,
    ) -> TurnState;
    fn is_need_avoid_bags(
        &self,
        cp: &Seat,
        round: &Round,
        turn_trick_state: &TurnState,
        hand_pile_state: &TurnHandPileState,
        limit_bag:i16
    ) -> bool;

    fn compute_rule_type(
        &self,
        cp: &Seat,
        round: &Round,
        turn_trick_state: &TurnState,
        hand_pile_state: &TurnHandPileState,
        is_attack_nil: bool,
        limit_bag:i16
    ) -> EmAIRule;

    fn compute_rule_point(
        &self,
        card_weights: &mut Vec<CardWeight>,
        table: &mut Table,
        round: &Round,
        cp: &Seat,
        hand_pile_state: &TurnHandPileState,
        turn_trick_state: &TurnState,
        ai_rule: EmAIRule,
    );
}

pub struct AiPlayNormal;

impl IAiPlayMode for AiPlayNormal {
    fn get_turn_trick_state(
        &self,
        seat_id: usize,
        table: &Table,
        round: &Round,
        _playable: &Vec<PokerCard>,
        // history_suit_map: PokerCards,
    ) -> TurnState {
        let mut turn_trick_state = TurnState::new();
        let player = &round.seats[seat_id];
        let player_id = seat_id;
        let leading_player_id = round.cur_turn().leading_id;
        let num = Utils::get_next_player_id(leading_player_id);
        let num2 = Utils::get_prev_player_id(leading_player_id);
        let num3 = Utils::get_partner_player_id(player_id);
        let num4 = Utils::get_prev_player_id(player_id);
        let num5 = Utils::get_next_player_id(player_id);

        turn_trick_state.partner_player_id = num3;
        turn_trick_state.pre_player_id = num4;
        turn_trick_state.next_player_id = num5;

        if player_id == leading_player_id {
            turn_trick_state.is_leading_player = true;
        } else if player_id == num2 {
            turn_trick_state.is_leading_pre_player_id = true;
        } else if player_id == num {
            turn_trick_state.is_leading_next_player_id = true;
        } else {
            turn_trick_state.is_leading_partner = true;
        }

        let partner_seat = &round.seats[num3];
        let prev_seat = &round.seats[num4];
        let next_seat = &round.seats[num5];

        turn_trick_state.is_opponents_nil = (prev_seat.bid.unwrap() == 0 && prev_seat.tricks == 0)
            || (next_seat.bid.unwrap() == 0 && next_seat.tricks == 0);

        let num6 = (player.bid.unwrap() + partner_seat.bid.unwrap()) as i16;
        let num7 = (player.tricks + partner_seat.tricks) as i16;

        turn_trick_state.is_team_overtrick = num7 >= num6;

        if !turn_trick_state.is_team_overtrick {
            turn_trick_state.team_bt_delta = num6 - num7;
        }

        turn_trick_state.team_bid = num6;

        let num6 = (prev_seat.bid.unwrap() + next_seat.bid.unwrap()) as i16;
        let num7 = (prev_seat.tricks + next_seat.tricks) as i16;

        turn_trick_state.is_other_overtirck = num7 >= num6;

        if !turn_trick_state.is_other_overtirck {
            turn_trick_state.other_bt_delta = num6 - num7;
        }

        turn_trick_state.other_bid = num6;

        //获取上一局的round的分数和bag
        match table.rounds.last() {
            Some(round) => {
                let team_score = &round.teams[0];
                turn_trick_state.team_match_score = team_score.match_score;
                turn_trick_state.team_total_bags = team_score.total_bags;

                let team_score2 = &round.teams[1];
                turn_trick_state.other_match_score = team_score2.match_score;
                turn_trick_state.other_total_bags = team_score2.total_bags;
            }
            None => {}
        }
        turn_trick_state
    }
    fn is_need_avoid_bags(
        &self,
        _cp: &Seat,
        _round: &Round,
        turn_trick_state: &TurnState,
        _hand_pile_state: &TurnHandPileState,
        limit_bag:i16
    ) -> bool {
        let flag = turn_trick_state.is_team_overtrick;
        if turn_trick_state.other_bt_delta > 0 {
            //对方没达成 自己不超袋的情况 可以优先得分
            if turn_trick_state.team_total_bags+1 < limit_bag{
                return false;
            }
        }
        // if !flag
        //     && (cp.tricks >= cp.bid.unwrap()
        //         || cp.tricks + hand_pile_state.spades_count >= cp.bid.unwrap())
        // {
        //     let partner_player = &round.seats[Utils::get_partner_player_id(cp.id)];
        //     info!("is_need_avoid_bags: {} {}", cp.tricks, cp.bid.unwrap());
        //     let card_len = cp.cards.len() as i16;
        //     let num = cp.tricks - cp.bid.unwrap();
        //     let num2 = card_len as i16 - turn_trick_state.team_bt_delta;

        //     //丢掉AK的数量会影响是否要避免bag
        //     if (card_len > turn_trick_state.team_bt_delta
        //         && partner_player.num_of_ak_lost_to_rival <= 0)
        //         || num >= partner_player.num_of_ak_lost_to_rival
        //     {
        //         //这里决定 没获取足够分数 剩余多少张牌开始避袋策略
        //         if num2 > turn_trick_state.team_bid + 2 {
        //             flag = true;
        //         }
        //     }
        // }
        flag
    }

    fn compute_rule_type(
        &self,
        cp: &Seat,
        round: &Round,
        turn_trick_state: &TurnState,
        hand_pile_state: &TurnHandPileState,
        is_attack_nil: bool,
        limit_bag:i16
    ) -> EmAIRule {
        let partner_id = Utils::get_partner_player_id(cp.id);
        let partner_player = &round.seats[partner_id];

        let mut rule_type;
        if cp.bid.unwrap() == 0 {
            rule_type = EmAIRule::PlayNil;
        } else if partner_player.bid.unwrap() == 0 {
            rule_type = EmAIRule::CoverNil;
        } else if self.is_need_avoid_bags(&cp, round, turn_trick_state, hand_pile_state,limit_bag) {
            if is_attack_nil && turn_trick_state.is_opponents_nil {
                rule_type = EmAIRule::AttackNilAndAvoidBags;
            } else {
                rule_type = EmAIRule::AvoidBags;
            }
        } else if is_attack_nil && turn_trick_state.is_opponents_nil {
            rule_type = EmAIRule::AttackNilAndReachBid;
        } else {
            rule_type = EmAIRule::ReachBid;
        }
        if rule_type == EmAIRule::PlayNil {
            if cp.tricks > 0 {
                rule_type = EmAIRule::AvoidBags;
            }
        } else if rule_type == EmAIRule::CoverNil {
            if partner_player.tricks > 0 {
                let flag = self.is_need_avoid_bags(cp, round, turn_trick_state, hand_pile_state,limit_bag);
                if !is_attack_nil {
                    if flag {
                        rule_type = EmAIRule::AvoidBags;
                    } else {
                        rule_type = EmAIRule::ReachBid;
                    }
                } else if flag && !is_need_priority_attack_nil(turn_trick_state,limit_bag) {
                    if turn_trick_state.is_opponents_nil {
                        rule_type = EmAIRule::AttackNilAndAvoidBags;
                    } else {
                        rule_type = EmAIRule::AvoidBags;
                    }
                } else if rule_type != EmAIRule::None {
                    if turn_trick_state.is_opponents_nil {
                        rule_type = EmAIRule::AttackNilAndReachBid;
                    } else {
                        rule_type = EmAIRule::ReachBid;
                    }
                }
            }
        }

        //如果是reachbid 可以看手牌数量和bag情况决定是否进攻对方的bag
        if rule_type == EmAIRule::ReachBid {
            if cp.cards.len() as i16 > turn_trick_state.team_bt_delta + 4
                && turn_trick_state.other_total_bags >= 8
            {
                rule_type = EmAIRule::AttackBags;
            }
        }
        rule_type
    }

    fn compute_rule_point(
        &self,
        card_weights: &mut Vec<CardWeight>,
        table: &mut Table,
        round: &Round,
        cp: &Seat,
        hand_pile_state: &TurnHandPileState,
        turn_trick_state: &TurnState,
        ai_rule: EmAIRule,
    ) {
        //根据枚举生成对应的类型
        let mut re = RuleEasy;
        let mut rb = RuleReachBid;
        let mut rab = RuleAvoidBags;
        let mut rpl = RulePlayNil;
        let mut rcn = RuleCoverNil;
        let mut ra1 = RuleAttackNilAndReachBid;
        let mut ra2 = RuleAttackNilAndAvoidBags;
        let mut rbg = RuleAttackBag;

        let rule: &mut dyn IRule = match ai_rule {
            EmAIRule::None => &mut re,
            EmAIRule::ReachBid=> &mut rb,
            EmAIRule::AvoidBags => &mut rab,
            EmAIRule::PlayNil => &mut rpl,
            EmAIRule::CoverNil => &mut rcn,
            EmAIRule::AttackNilAndReachBid => &mut ra1,
            EmAIRule::AttackNilAndAvoidBags => &mut ra2,
            EmAIRule::AttackBags => &mut rbg,
        };

        if turn_trick_state.is_leading_player {
            rule.give_points_as_leader_by_player(
                cp.id,
                table,
                round,
                hand_pile_state,
                turn_trick_state,
                card_weights,
            );
        } else if hand_pile_state
            .void_suits
            .contains(&round.cur_turn().leading_card().card.get_suit())
        {
            rule.give_points_to_voided_suit_by_player(
                cp.id,
                table,
                round,
                hand_pile_state,
                turn_trick_state,
                card_weights,
            );
        } else if turn_trick_state.is_leading_pre_player_id {
            rule.give_points_as_last_to_play_by_player(
                cp.id,
                table,
                round,
                hand_pile_state,
                turn_trick_state,
                card_weights,
            );
        } else {
            rule.give_points_as_following_suit_by_player(
                cp.id,
                table,
                round,
                hand_pile_state,
                turn_trick_state,
                card_weights,
            );
        }
    }
}

pub struct AiPlaySolo;

impl IAiPlayMode for AiPlaySolo {
    fn get_turn_trick_state(
        &self,
        seat_id: usize,
        table: &Table,
        round: &Round,
        _playable: &Vec<PokerCard>,
        // history_suit_map: PokerCards,
    ) -> TurnState {
        let mut turn_trick_state = TurnState::new();
        let player = &round.seats[seat_id];
        let player_id = seat_id;
        let leading_player_id = round.cur_turn().leading_id;
        let num = Utils::get_next_player_id(leading_player_id);
        let num2 = Utils::get_prev_player_id(leading_player_id);
        let num3 = Utils::get_partner_player_id(player_id);
        let num4 = Utils::get_prev_player_id(player_id);
        let num5 = Utils::get_next_player_id(player_id);

        turn_trick_state.partner_player_id = num3;
        turn_trick_state.pre_player_id = num4;
        turn_trick_state.next_player_id = num5;

        if player_id == leading_player_id {
            turn_trick_state.is_leading_player = true;
        } else if player_id == num2 {
            turn_trick_state.is_leading_pre_player_id = true;
        } else if player_id == num {
            turn_trick_state.is_leading_next_player_id = true;
        } else {
            turn_trick_state.is_leading_partner = false;
        }

        let partner_seat = &round.seats[num3];
        let prev_seat = &round.seats[num4];
        let next_seat = &round.seats[num5];

        turn_trick_state.is_opponents_nil = (prev_seat.bid.unwrap() == 0 && prev_seat.tricks == 0)
            || (next_seat.bid.unwrap() == 0 && next_seat.tricks == 0
                || partner_seat.bid.unwrap() == 0 && partner_seat.tricks == 0);

        let num6 = player.bid.unwrap() as i16;
        let num7 = player.tricks as i16;

        turn_trick_state.is_team_overtrick = num7 >= num6;

        if !turn_trick_state.is_team_overtrick {
            turn_trick_state.team_bt_delta = num6 - num7;
        }

        turn_trick_state.team_bid = num6;

        //获取上一局的round的分数和bag
        match table.rounds.last() {
            Some(round) => {
                let team_score = &round.teams[0];
                turn_trick_state.team_match_score = team_score.match_score;
                turn_trick_state.team_total_bags = team_score.total_bags;
            }
            None => {}
        }
        turn_trick_state
    }
    fn is_need_avoid_bags(
        &self,
        _cp: &Seat,
        _round: &Round,
        turn_trick_state: &TurnState,
        _hand_pile_state: &TurnHandPileState,
        _limit_bag:i16
    ) -> bool {
        let flag = turn_trick_state.is_team_overtrick;
        if turn_trick_state.is_other_overtirck{
            return flag;
        }
        // if !flag
        //     && (cp.tricks >= cp.bid.unwrap()
        //         || cp.tricks + hand_pile_state.spades_count >= cp.bid.unwrap())
        // {
        //     info!("is_need_avoid_bags: {} {}", cp.tricks, cp.bid.unwrap());
        //     let card_len = cp.cards.len() as i16;
        //     let num2 = card_len as i16 - turn_trick_state.team_bt_delta;
        //     //这里决定 没获取足够分数 剩余多少张牌开始避袋策略
        //     if num2 > turn_trick_state.team_bid + 2 {
        //         flag = true;
        //     }
        // }
        flag
    }

    fn compute_rule_type(
        &self,
        cp: &Seat,
        round: &Round,
        turn_trick_state: &TurnState,
        hand_pile_state: &TurnHandPileState,
        is_attack_nil: bool,
        limit_bag:i16
    ) -> EmAIRule {
        let mut rule_type;
        if cp.bid.unwrap() == 0 {
            rule_type = EmAIRule::PlayNil;
        } else if self.is_need_avoid_bags(&cp, &round, turn_trick_state, hand_pile_state,limit_bag) {
            if is_attack_nil && turn_trick_state.is_opponents_nil {
                rule_type = EmAIRule::AttackNilAndAvoidBags;
            } else {
                rule_type = EmAIRule::AvoidBags;
            }
        } else if is_attack_nil && turn_trick_state.is_opponents_nil {
            rule_type = EmAIRule::AttackNilAndReachBid;
        } else {
            rule_type = EmAIRule::ReachBid;
        }
        if rule_type == EmAIRule::PlayNil {
            if cp.tricks > 0 {
                rule_type = EmAIRule::AvoidBags;
            }
        }
        rule_type
    }

    fn compute_rule_point(
        &self,
        card_weights: &mut Vec<CardWeight>,
        table: &mut Table,
        round: &Round,
        cp: &Seat,
        hand_pile_state: &TurnHandPileState,
        turn_trick_state: &TurnState,
        ai_rule: EmAIRule,
    ) {
        //根据枚举生成对应的类型
        let mut re = RuleEasy;
        let mut rpl = RulePlayNil;
        let mut rcn = RuleCoverNil;
        let mut rbs = RuleReachBidSolo;
        let mut rabs = RuleAvoidBagsSolo;
        let mut rcns = RuleCoverNilSolo;
        let mut ra1s = RuleAttackNilAndReachBidSolo;
        let mut ra2s = RuleAttackNilAndAvoidBagsSolo;
        let mut rbgs = RuleAttackBagSolo;

        let rule: &mut dyn IRule = match (ai_rule, 2) {
            (EmAIRule::None, 1 | 2) => &mut re,
            (EmAIRule::ReachBid, 2) => &mut rbs,
            (EmAIRule::AvoidBags, 2) => &mut rabs,
            (EmAIRule::PlayNil, 1 | 2) => &mut rpl,
            (EmAIRule::CoverNil, 1) => &mut rcn,
            (EmAIRule::CoverNil, 2) => &mut rcns,
            (EmAIRule::AttackNilAndReachBid, 2) => &mut ra1s,
            (EmAIRule::AttackNilAndAvoidBags, 2) => &mut ra2s,
            (EmAIRule::AttackBags, 2) => &mut rbgs,
            _ => &mut rbs,
        };

        if turn_trick_state.is_leading_player {
            rule.give_points_as_leader_by_player(
                cp.id,
                table,
                round,
                hand_pile_state,
                turn_trick_state,
                card_weights,
            );
        } else if hand_pile_state
            .void_suits
            .contains(&round.cur_turn().leading_card().card.get_suit())
        {
            rule.give_points_to_voided_suit_by_player(
                cp.id,
                table,
                round,
                hand_pile_state,
                turn_trick_state,
                card_weights,
            );
        } else if turn_trick_state.is_leading_pre_player_id {
            rule.give_points_as_last_to_play_by_player(
                cp.id,
                table,
                round,
                hand_pile_state,
                turn_trick_state,
                card_weights,
            );
        } else {
            rule.give_points_as_following_suit_by_player(
                cp.id,
                table,
                round,
                hand_pile_state,
                turn_trick_state,
                card_weights,
            );
        }
    }
}

fn is_need_priority_attack_nil(turn_trick_state: &TurnState,limit_bag:i16) -> bool {
    let mut flag = !turn_trick_state.is_other_overtirck;
    if flag {
        let num = turn_trick_state.team_bid + turn_trick_state.other_bid;
        if num < 11 {
            flag = false;
        } else {
            let num2 = 13 - num - 1;
            if turn_trick_state.team_total_bags + num2 >= limit_bag-1 {
                return false;
            }
        }
    }
    flag
}
